package com.lsh.oms.core.service.order.frozen;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lsh.base.common.json.JsonUtils;
import com.lsh.base.common.model.CommonResult;
import com.lsh.base.lang.Maps;
import com.lsh.oms.api.model.es.OrderHeadForEs;
import com.lsh.oms.api.model.order.OrderReceiptDTO;
import com.lsh.oms.api.model.other.OrderShippingDetailDto;
import com.lsh.oms.api.model.other.OrderShippingHeadDto;
import com.lsh.oms.core.constant.ReturnCode;
import com.lsh.oms.core.enums.OrderStatus;
import com.lsh.oms.core.enums.ShippingStatus;
import com.lsh.oms.core.enums.UserType;
import com.lsh.oms.core.exception.BusinessException;
import com.lsh.oms.core.model.order.*;
import com.lsh.oms.core.proxy.service.EsProxy;
import com.lsh.oms.core.records.core.ReturnRequestRepository;
import com.lsh.oms.core.service.order.AbstractOrderService;
import com.lsh.oms.core.service.order.OrderFactory;
import com.lsh.oms.core.service.other.RoOrderService;
import com.lsh.oms.core.service.other.ShippingOrderService;
import com.lsh.oms.core.service.other.SignOrderService;
import com.lsh.oms.core.service.sign.core.SignService;
import com.lsh.oms.core.service.sms.SmsService;
import com.lsh.oms.core.utils.IdGenerator;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.lsh.oms.core.records.core.ReturnRequest.Occasion.BEFORE_SIGN;
import static java.util.stream.Collectors.toList;

/**
 * 订单发货service
 *
 * @author peter
 */
@Service
public class OrderReceiptFrogenService extends AbstractOrderService {

    private static Logger logger = LoggerFactory.getLogger(OrderReceiptH5Service.class);

    @Autowired
    private ShippingOrderService shippingService;

    @Resource
    private SignService signs;

    @Autowired
    private SignOrderService signOrderService;

    @Autowired
    private ReturnRequestRepository returnRequestRepository;

    @Autowired
    private RoOrderService roOrderService;

    @Autowired
    private EsProxy esProxy;

    @Autowired
    private SmsService smsService;


    /**
     * 创建签收￿单
     */
    @Transactional
    public CommonResult<Object> createReceiptOrder(OrderReceiptDTO receiptDTO, OrderHead orderHead, String logSign) {
        OrderShippingHeadDto orderShippingHeadDto = receiptDTO.getOrderShippingHeadDto();
        Long orderCode = orderHead.getOrderCode();
        OrderShippingHeadWithBLOBs osh = shippingService.getBolbs(orderCode);
        if (osh == null) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "此订单未生成发货单.请查询");
        }

        OrderSignHead oshHead = signOrderService.getSignHeadByOrderId(orderCode, false);
        CommonResult<Object> res = new CommonResult<>();
        if (oshHead != null) {

            if (oshHead.getPayStatus() == 2 && oshHead.getStatus() == 2) {
                throw new BusinessException(ReturnCode.REQUEST_FAIL, "此订单已签收(支付)不能再次签收.");
            }

            this.validOrderSignEs(oshHead, logSign);
        }

        OrderRoHead orderRoHead = roOrderService.getHead(orderCode);
        if (orderRoHead != null) {
            this.validOrderRoEs(orderRoHead, logSign);
        }

        List<OrderShippingDetail> shippingDetails = shippingService.getDetails(osh.getShippingOrderId());
        logger.info("shippingDetails is " + JSON.toJSONString(shippingDetails));

        List<Map<String, Object>> items = Optional.ofNullable(orderShippingHeadDto).map($ -> toCalServiceSukList($.getDetails())).orElse(Collections.emptyList());
        if (items.isEmpty()) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "请求签收计算服务报文为空。");
        }

        JSONObject extjson = JSON.parseObject(orderHead.getExt());
        String providerId = extjson.getString("providerId");
        if (StringUtils.isBlank(providerId)) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "订单信息中没有供商信息，请联系相关人员处理");
        }

        Map<Integer, OrderShippingDetail> detailMap = shippingDetails.stream().collect(Collectors.toMap(OrderShippingDetail::getItemCode, shippingDetail -> shippingDetail));

        //请求商品服务 商品信息
//        Map<Long, Good> item2GoodsMaps = this.goodsServiceProxy.requestItem2Goods(orderCode, orderHead.getParentOrderCode(), providerId, orderHead.getVenderId(), logSign);
        CalOrderContent calOrderContent = this.orderReceipt(items, osh, shippingDetails, logSign);

        CalOrderReceiptContent receipt = calOrderContent.getReceipt();
        CalOrderReturnContent returnContent = calOrderContent.getReturnContent();
        if (returnContent != null) {
            logger.info(orderCode + "-returnOrder-" + JSON.toJSONString(returnContent));
        }

        CalOrderReceiptHead head = receipt.getHead();
        List<CalOrderReceiptDetail> detailList = receipt.getDetailList();

        oshHead = OrderFactory.createSignHead(orderCode, orderHead, osh, head, null);
        oshHead.setVenderId(orderHead.getVenderId());

        long receiptOrderId = IdGenerator.genId();
        oshHead.setReceiptOrderId(receiptOrderId);
        JSONObject extObject = head.getExt();
        JSONObject headInfo = extObject.getJSONObject("head_info");
        headInfo.put("floor_money", String.valueOf(oshHead.getFloorMoney().setScale(2, BigDecimal.ROUND_HALF_UP)));
        headInfo.put("money", String.valueOf(oshHead.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP)));
        extObject.put("head_info", headInfo);
        oshHead.setExt(extObject.toJSONString());
        List<OrderSignDetail> signDetails = OrderFactory.receiptDetails(detailList, orderHead, receiptOrderId, detailMap, oshHead, logSign);

        oshHead.setDetails(signDetails);
        boolean successFlag;
        boolean kaFlag = (OrderFactory.getUserType(orderHead) == UserType.KA.getIndex());
        try {
            Integer paytype = oshHead.getPayType();
            boolean statusFlag = false;
            if (paytype != null && paytype >= 1) {
                statusFlag = true;
            }

            logger.info(logSign + " 生成签收单开始" + orderHead.getOrderCode());
            successFlag = signOrderService.saveOrUpdateData(oshHead, logSign, statusFlag, kaFlag);
            logger.info(logSign + " 生成签收单结束" + orderHead.getOrderCode());

            signs.findById(oshHead.getReceiptOrderId()).filter($ -> $.paid() && !kaFlag).ifPresent($ -> {
                this.createRo(returnContent, orderHead, receiptDTO);
                signOrderService.createIssueTask($);
            });
        } catch (Throwable e) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "添加签收单失败");
        }

        if (successFlag) {

            Map<String, Object> respMap = new HashMap<>();
            respMap.put("flag", true);
            BigDecimal sourceMoney = head.getMoney();
            respMap.put("receipt_order_id", oshHead.getReceiptOrderId());

            DecimalFormat df = new DecimalFormat("0.000");
            BigDecimal[] floorMoneyList = sourceMoney.divideAndRemainder(BigDecimal.ONE);
            BigDecimal floorMoney = new BigDecimal(df.format(floorMoneyList[1]));
            BigDecimal real_pay_money = sourceMoney.subtract(floorMoney);

            if (OrderFactory.getUserType(orderHead) == UserType.KA.getIndex()) {
                respMap.put("real_pay_money", BigDecimal.ZERO);
                respMap.put("money", sourceMoney);
            } else {
                respMap.put("real_pay_money", sourceMoney);
                respMap.put("money", sourceMoney);
            }
            Integer paytype = oshHead.getPayType();

            if (paytype != null) {
                respMap.put("pay_type", paytype);
            } else {
                respMap.put("pay_type", 0);
            }
            BigDecimal saled_money = head.getDiscountedMoney();

            BigDecimal coupon_money = saled_money.subtract(real_pay_money);
            respMap.put("total_coupon_money", coupon_money);
            res.setData(respMap);
        }

        Integer payType = oshHead.getPayType();
        boolean statusFlag = false;
        if (payType != null && payType >= 1) {
            statusFlag = true;
        }

        this.notifyEs(orderCode, osh, OrderFactory.getMarketName(orderHead), OrderFactory.getProviderId(orderHead), logSign, statusFlag, kaFlag);

//        if (kaFlag) {
        this.smsMis(oshHead, orderHead, logSign);
//        }

        res.setCode(ReturnCode.REQUEST_SUCCESS);

        return res;
    }

    private List<Map<String, Object>> toCalServiceSukList(List<OrderShippingDetailDto> shippingDetails) {
        return Optional.ofNullable(shippingDetails).map($ -> $.stream().map($$ -> Maps.of("item_code", $$.getItemId(), "sku_id", $$.getSkuId(), "qty", $$.getQty())).collect(toList())).orElse(Collections.emptyList());
    }


    private boolean createRo(CalOrderReturnContent returnContent, OrderHead orderHead, OrderReceiptDTO receiptDTO) {
        try {
            logger.info("生成反仓单开始" + orderHead.getOrderCode());
            //反仓单
            if (returnContent != null) {
                logger.info("return order with request: " + JSON.toJSONString(returnContent));
                // build反仓单信息
                Optional.ofNullable(returnContent.getDetail()).ifPresent($ -> {
                    Map<String, Object> request = new HashMap<>();
                    request.put("order", Maps.of("id", orderHead.getOrderCode()));
                    List<Map<String, Object>> details = new ArrayList<>();
                    $.forEach(dto -> {
                        Map<String, Object> item = new HashMap<>();
                        item.put("quantity", dto.getQty());
                        item.put("item_code", dto.getItemCode());
                        item.put("opinion", Maps.of("approved", true, "discarded", false, "notes", ""));
                        item.put("reason", Maps.of("code", "SHORTCUT", "notes", "", "images", Collections.emptyList()));
                        details.add(item);
                    });
                    request.put("occasion", BEFORE_SIGN.name());
                    request.put("details", details);
                    request.put("party", receiptDTO.getParty());
                    returnRequestRepository.create(request);
                });
            }
            logger.info("生成反仓单结束");
        } catch (Exception e) {
            logger.info("生成反仓单异常", e);
            return false;
        }
        return true;
    }

    /**
     * 创建签收单
     *
     * @param orderHead 订单信息
     * @param logSign   唯一标识
     * @return 返回信息
     */
    @Transactional
    public CommonResult<Object> createReceiptFromShip(OrderHead orderHead, String logSign) {

        Long orderCode = orderHead.getOrderCode();
        OrderShippingHeadWithBLOBs osh = shippingService.getBolbs(orderCode);
        if (osh == null) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "此订单未生成发货单.请查询");
        }

        OrderSignHead oshHead = signOrderService.getSignHeadByOrderId(orderCode, false);
        CommonResult<Object> res = new CommonResult<>();
        if (oshHead != null) {
            if (oshHead.getPayStatus() == 2) {
                throw new BusinessException(ReturnCode.REQUEST_FAIL, "签收单已支付不能再次签收");
            }

            res.setData(oshHead);
            res.setCode(ReturnCode.REQUEST_SUCCESS);
            return res;
        }

        Integer receiptTime = null;

        OrderSignHead orderSignHead = this.createReceiptBillFromShip(orderHead, osh, false, receiptTime, logSign);
        if (orderSignHead != null) {

            res.setData(orderSignHead);

            Integer payType = orderSignHead.getPayType();
            boolean statusFlag = false;
            if (payType != null && payType >= 1) {
                statusFlag = true;
            }

            boolean kaFlag = (OrderFactory.getUserType(orderHead) == UserType.KA.getIndex());
            this.notifyEs(orderCode, osh, OrderFactory.getMarketName(orderHead), OrderFactory.getProviderId(orderHead), logSign, statusFlag, kaFlag);

            res.setCode(ReturnCode.REQUEST_SUCCESS);
//            String dmallType = orderHead.addressProperties().getString("dMallOrderType");
//            if(StringUtils.isEmpty(dmallType)){
//                dmallType = "99";
//            }

            this.smsMis(orderSignHead, orderHead, logSign);

        } else {
            res.setCode(ReturnCode.REQUEST_FAIL);
        }

        return res;
    }

    protected void smsMis(OrderSignHead oshHead, OrderHead orderHead, String logSign) {
        try {

            this.smsService.toSignSMS(oshHead, orderHead, logSign);

        } catch (Exception e) {
            logger.info("异步处理 错误");
        }

    }

    /**
     * @param orderHead
     * @param osh
     * @param logSign
     * @return
     */
    private OrderSignHead createReceiptBillFromShip(OrderHead orderHead, OrderShippingHeadWithBLOBs osh, boolean statusFlag, Integer receiptTime, String logSign) {
        Long orderCode = orderHead.getOrderCode();
        List<OrderShippingDetail> shippingDetails = shippingService.getDetails(osh.getShippingOrderId());

        JSONObject extjson = JSON.parseObject(orderHead.getExt());
        String providerId = extjson.getString("providerId");
        if (StringUtils.isBlank(providerId)) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "订单信息中没有供商信息，请联系相关人员处理");
        }

        Map<Integer, OrderShippingDetail> detailMap = shippingDetails.stream().collect(Collectors.toMap(OrderShippingDetail::getItemCode, shippingDetail -> shippingDetail));

        //请求商品服务 商品信息
//        Map<Long, Good> item2GoodsMaps = this.goodsServiceProxy.requestItem2Goods(orderCode, orderHead.getParentOrderCode(), providerId, osh.getVenderId(), logSign);
        //TODO:请求签收计算服务
        CalOrderContent calOrderContent = this.orderReceipt(Collections.emptyList(), osh, shippingDetails, logSign);
        CalOrderReceiptContent receipt = calOrderContent.getReceipt();
        CalOrderReturnContent calOrderReturnContent = calOrderContent.getReturnContent();
        if (calOrderReturnContent != null) {
            logger.info(orderCode + "-returnOrder-" + JSON.toJSONString(calOrderReturnContent));
        }

        CalOrderReceiptHead head = receipt.getHead();
        List<CalOrderReceiptDetail> detailList = receipt.getDetailList();
        OrderSignHead oshHead = OrderFactory.createSignHead(orderCode, orderHead, osh, head, receiptTime);
        Integer paytype = oshHead.getPayType();
        if (paytype != null && paytype >= 1) {
            statusFlag = true;
        }
        long receiptOrderId = IdGenerator.genId();
        oshHead.setReceiptOrderId(receiptOrderId);

        JSONObject extObject = head.getExt();
        JSONObject headInfo = extObject.getJSONObject("head_info");
        headInfo.put("floor_money", String.valueOf(oshHead.getFloorMoney().setScale(2, BigDecimal.ROUND_HALF_UP)));
        headInfo.put("money", String.valueOf(oshHead.getMoney().setScale(2, BigDecimal.ROUND_HALF_UP)));
        //黑狗签收  1 已签收,0未签收
        headInfo.put("hg_receipt_status", "0");
        extObject.put("head_info", headInfo);
        oshHead.setExt(extObject.toJSONString());
        List<OrderSignDetail> signDetails = OrderFactory.receiptDetails(detailList, orderHead, receiptOrderId, detailMap, oshHead, logSign);

        oshHead.setDetails(signDetails);

        boolean kaFlag = (OrderFactory.getUserType(orderHead) == UserType.KA.getIndex());

        if (!signOrderService.saveOrUpdateData(oshHead, logSign, statusFlag, kaFlag)) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "添加签收单失败");
        }

        return oshHead;
    }

    /**
     * @param orderReceiptItem
     * @param osh
     * @param shippingDetails
     * @param orderHead
     * @param logSign
     * @return
     */
//    private CalOrderContent orderSign(Map<Long, BigDecimal> orderReceiptItem, OrderShippingHeadWithBLOBs osh, List<OrderShippingDetail> shippingDetails, OrderHead orderHead, String logSign) {
//
//        CalOrderContent calOrderContent;
//        try {
//            calOrderContent = orderReceiptByItem(orderReceiptItem, osh, shippingDetails, logSign);
//            if (calOrderContent == null || calOrderContent.getReceipt() == null) {
//                logger.info(logSign + "订单号" + orderHead.getOrderCode() + ",请求签收计算服务返回报文为空。");
//                throw new BusinessException(ReturnCode.REQUEST_FAIL, "请求签收计算服务返回报文为空。");
//            }
//        } catch (Throwable e) {
//            logger.error(logSign + "订单号" + orderHead.getOrderCode() + ",请求签收计算服务失败。");
//            logger.error(e.getMessage(), e);
//            throw new BusinessException(ReturnCode.REQUEST_FAIL, "请求签收计算服务失败。");
//        }
//
//        return calOrderContent;
//    }

    /**
     * 通知es
     *
     * @param orderCode 订单号
     * @param osh       发货单详情
     * @param logSign   唯一标识
     */
    protected void notifyEs(Long orderCode, OrderShippingHeadWithBLOBs osh, String marketName, String provideId, String logSign, boolean statusFalg, boolean flagKA) {
        OrderSignHead oshHead = signOrderService.getSignHeadByOrderId(orderCode, false);

        try {
            if (oshHead == null) {
                logger.info("订单" + orderCode + "的签收信息为null");
            }

            if (StringUtils.isNotBlank(marketName)) {
                oshHead.setMarketName(marketName);
            }

            oshHead.setProviderId(provideId);
            JSONObject extObject = JSON.parseObject(oshHead.getExt());
            JSONObject headInfo = extObject.getJSONObject("head_info");
            logger.info("订单-" + orderCode + " 的headInfo " + headInfo);

            oshHead.setFinalMoney(oshHead.getMoney());
            logger.info(logSign + "ES入参新建签收单是-- " + JsonUtils.obj2Json(oshHead));
            esProxy.createIndex(oshHead, logSign);
            if (statusFalg || flagKA) {

                OrderShippingHeadWithBLOBs oshEs = new OrderShippingHeadWithBLOBs();
                oshEs.setShippingOrderId(osh.getShippingOrderId());
                oshEs.setStatus(ShippingStatus.DELIVERED.getIndex());
                logger.info(logSign + "ES入参修改发货是-- " + JsonUtils.obj2Json(oshEs));
                esProxy.editIndex(oshEs, logSign);
                OrderHeadForEs ohEs = new OrderHeadForEs();
                ohEs.setOrderCode(orderCode);
                ohEs.setOrderStatus(OrderStatus.ORDER_SIGN.getIndex());
                logger.info(logSign + "ES入参修改订单是-- " + JsonUtils.obj2Json(ohEs));
                esProxy.editIndex(ohEs, logSign);
            }

        } catch (Throwable e) {
            logger.info(logSign + "订单号" + orderCode + ",生成发货单同步es失败。");
            logger.info(e.getMessage(), e);
        }
    }


    @Transactional
    public CommonResult<Object> isCreateReceiptBill(OrderHead orderHead) {

        OrderShippingHeadWithBLOBs osh = shippingService.getBolbs(orderHead.getOrderCode());
        if (osh == null) {
            throw new BusinessException(ReturnCode.REQUEST_FAIL, "此订单未生成发货单.请查询");
        }

        if (OrderFactory.getUserType(orderHead) == UserType.KA.getIndex()) {
            return this.isCreateReceiptBillForKA();
        } else {
            OrderSignHead oshHead = signOrderService.getSignHeadByOrderId(orderHead.getOrderCode(), false);
            return isCreateReceiptBillForNormal(oshHead);
        }

    }

    /**
     * @return
     */
    private CommonResult<Object> isCreateReceiptBillForKA() {
        CommonResult<Object> res = new CommonResult<>();

        res.setCode(ReturnCode.REQUEST_SUCCESS);
        res.setMessage("ok");

        return res;
    }

    /**
     * @param oshHead
     * @return
     */
    private CommonResult<Object> isCreateReceiptBillForNormal(OrderSignHead oshHead) {
        CommonResult<Object> res = new CommonResult<>();
        if (oshHead != null && oshHead.getPayStatus() == 2) {
            res.setCode(ReturnCode.REQUEST_SUCCESS);
            res.setMessage("ok");
        } else {
            res.setCode(ReturnCode.RECEIPT_NO_DEAL);
            res.setMessage("暂无法操作签收，请先完成线上支付再重试。");
        }

        return res;
    }

    private void validOrderSignEs(OrderSignHead orderSignHead, String logSign) {
        OrderSignHead orderSignHeadDB = new OrderSignHead();
        orderSignHeadDB.setReceiptOrderId(orderSignHead.getReceiptOrderId());
        orderSignHeadDB.setIsValid(0);

        if (signOrderService.setValid(orderSignHeadDB, logSign)) {
            esProxy.editIndex(orderSignHeadDB, logSign);
        }

    }

    private void validOrderRoEs(OrderRoHead orderRoHead, String logSign) {

        OrderRoHead orderRoHeadDB = new OrderRoHead();
        orderRoHeadDB.setReturnOrderId(orderRoHead.getReturnOrderId());
        orderRoHeadDB.setIsValid(0);
        if (roOrderService.setValidReturn(orderRoHeadDB) > 0) {
            esProxy.editIndex(orderRoHeadDB, logSign);
        }

    }

}
